package com.grandtech.insurance.common.db.mybites.intercepts;


import com.grandtech.insurance.common.db.jdbc.sql.annotation.Table;
import com.grandtech.insurance.common.db.mybites.utils.ResultSetUtil;
import org.apache.ibatis.executor.resultset.DefaultResultSetHandler;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.plugin.*;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.List;
import java.util.Properties;


@Intercepts(value = {
        @Signature(
                type = ResultSetHandler.class,
                method = "handleResultSets",
                args = {Statement.class})
})
/**
 * 只有加了@Table注解的类才自己处理结果集
 */
public class MbResIntercept implements Interceptor {


    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object target = invocation.getTarget();
        Object res = null;
        if (target instanceof DefaultResultSetHandler) {
            DefaultResultSetHandler resultSetHandler = (DefaultResultSetHandler) target;
            // 利用反射获取参数对象 并判断是否需要拦截这个方法执行
            Class<?> clazz = annotation(resultSetHandler);
            Table table = clazz.getAnnotation(Table.class);
            if (table != null&&table.interceptResult()) {
                Statement statement = (Statement) invocation.getArgs()[0];
                return handlerResultSet(statement.getResultSet(), clazz);
            }
        }
        res = invocation.proceed();
        return res;
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        System.out.println(properties);
    }

    /**
     * 判断是否需要拦截
     *
     * @param resultSetHandler
     * @return
     */
    private Class<?> annotation(DefaultResultSetHandler resultSetHandler) {
        //使用反射获取DefaultResultSetHandler 中的私有成员变量mappedStatement
        Field field = ReflectionUtils.findField(DefaultResultSetHandler.class, "mappedStatement");
        field.setAccessible(true);
        Object val = null;
        try {
            val = field.get(resultSetHandler);
            if (val instanceof MappedStatement) {
                MappedStatement statement = (MappedStatement) val;
                List list = statement.getResultMaps();
                if (list.size() == 1) {
                    Object resultMap = list.get(0);
                    //resultMap 就是拦截的方法返回的类型，如果这个方法返回的类型为我们制定的类型就拦截
                    if (resultMap instanceof ResultMap) {
                        ResultMap map = (ResultMap) resultMap;
                        Class<?> clazz = map.getType();
                        return clazz;
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    //这个方法就是与jdbc中操作ResultSet
    private List<Object> handlerResultSet(ResultSet resultSet, Class<?> clazz) {
        Object result = null;
        if (resultSet != null) {
            try {
                result = ResultSetUtil.resultSet2List(resultSet, clazz);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                closeResultSet(resultSet);
            }
        }
        return (List<Object>) result;
    }

    private void closeResultSet(ResultSet resultSet) {
        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
